package com.dcstudy.redis.cachepenetration.bloomfilter;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2021-05-20 16:53
 *
 * 功能: 使用 redisson的布隆过滤器实现 白名单功能, 解决缓存穿透问题
 * 如果布隆过滤器中存在, 则进入 redis, mysql 将相应的内容查询出来返回给前端
 * 如果不存在, 则直接返回
 */
public class RedissonBloomFilterDemo {
    public static final int _1W = 10000;

    /**
     * 布隆过滤器里预计要插入多少数据
     */
    public static int size = 100 * _1W;
    /**
     * 误判率,它越小误判的个数也就越少
     */
    public static double fpp = 0.03;

    /**
     * jedis
     */
    static RedissonClient redissonClient = null;
    /**
     * redis版内置的布隆过滤器
     */
    static RBloomFilter rBloomFilter = null;

    @Resource
    RedisTemplate redisTemplate;


    static {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379").setDatabase(0);
        //构造redisson
        redissonClient = Redisson.create(config);
        //通过redisson构造rBloomFilter
        rBloomFilter = redissonClient.getBloomFilter("phoneListBloomFilter", new StringCodec());

        rBloomFilter.tryInit(size, fpp);

        // 1测试  布隆过滤器有 + redis有
        rBloomFilter.add("10086");
        redissonClient.getBucket("10086",new StringCodec()).set("chinamobile10086");
        //redisTemplate.opsForValue().set(10086, chinamobile10086) 类似

        // 2测试  布隆过滤器有 + redis无
        //rBloomFilter.add("10087");

        //3 测试 ，布隆过滤器无 + redis无

    }

    private static String getPhoneListById(String idNumber) {
        String result = null;
        if (idNumber == null) {
            return null;
        }
        //1 先去布隆过滤器里面查询
        if (rBloomFilter.contains(idNumber)) {
            //2 布隆过滤器里有，再去redis里面查询
            RBucket<String> rBucket = redissonClient.getBucket(idNumber, new StringCodec());
            result = rBucket.get();
            if (result != null) {
                return "i come from redis: " + result;
            } else {
                result = getPhoneListByMySQL(idNumber);
                if (result == null) {
                    return null;
                }
                // 重新将数据更新回redis
                redissonClient.getBucket(idNumber, new StringCodec()).set(result);
            }
            return "i come from mysql: " + result;
        }
        return result;
    }

    private static String getPhoneListByMySQL(String idNumber) {
        return "chinamobile" + idNumber;
    }


    public static void main(String[] args) {
        String phoneListById = getPhoneListById("10086");
        //String phoneListById = getPhoneListById("10087"); //请测试执行2次
//        String phoneListById = getPhoneListById("10088");
        System.out.println("------查询出来的结果： " + phoneListById);

        //暂停几秒钟线程
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redissonClient.shutdown();
    }


}
